home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / toswinsc.zoo / menu.c < prev    next >
C/C++ Source or Header  |  1992-10-27  |  15KB  |  721 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include <stdlib.h>
  13. #include <stddef.h>
  14. #include <string.h>
  15. #include <osbind.h>
  16. #include <ctype.h>
  17. #include <keycodes.h>
  18. #include "xgem.h"
  19.  
  20. char *about_string = "About...";
  21. char *desk_string = "TOSWIN";
  22. void (*about_func)() = 0;
  23.  
  24. /* local variables */
  25. static MENU     *curmenu = 0;    /* currently displayed menu */
  26. static MENU    *deskmenu = 0;    /* the whole menu bar, include " Desk " */
  27. static OBJECT    *menuobj = 0;    /* menu object for the displayed menu */
  28.  
  29. /*
  30.  * Create a menu with the given title. Under GEM, we automatically
  31.  * add a space before and after the title, for aesthetics. (This is
  32.  * done in fixmenu.)
  33.  */
  34.  
  35. MENU *
  36. create_menu(title)
  37.     const char *title;
  38. {
  39.     MENU *m;
  40.  
  41.     m = malloc(sizeof(MENU));
  42.     if (!m) return m;
  43.     m->next = 0;
  44.     m->title = strdup(title);
  45.     m->width = 0;
  46.     m->contents = 0;
  47.     m->index = 0;
  48.     return m;
  49. }
  50.  
  51. /*
  52.  * Destroy a menu, freeing any memory allocated for it.
  53.  */
  54.  
  55. void
  56. destroy_menu(menu)
  57.     MENU *menu;
  58. {
  59.     MENU *m;
  60.     ENTRY *e;
  61.  
  62.     if (curmenu && menu == curmenu) {
  63.         hide_menu();
  64.     }
  65.  
  66.     while (menu) {
  67.         m = menu; menu = m->next;
  68.         while ((e = m->contents)) {
  69.             m->contents = e->next;
  70.             free(e->entry);
  71.             free(e);
  72.         }
  73.         free(m);
  74.     }
  75. }
  76.  
  77. /*
  78.  * Add a new entry to a menu. We automatically add 2 spaces before and
  79.  * 2 after the menu entry string, for aesthetics, in fixmenu, and
  80.  * any special key symbols are also placed there; so the user doesn't
  81.  * need to worry about these details.
  82.  * NOTE: the string given as `entry' need not remain around permanently;
  83.  * we duplicate it just to be on the safe side.
  84.  * Returns: the newly added entry, or NULL on failure.
  85.  */
  86.  
  87. ENTRY *
  88. add_entry( m, entry, f, arg, key, state)
  89.     MENU *m;
  90.     char *entry;
  91.     void (*f)();
  92.     void *arg;
  93.     int key, state;
  94. {
  95.     ENTRY *e, **ep;
  96.  
  97.     e = malloc(sizeof(ENTRY));
  98.     if (!e) return 0;
  99.     ep = &m->contents;
  100.     while (*ep) {
  101.         ep = &((*ep)->next);
  102.     }
  103.     *ep = e;
  104.     e->next = 0;
  105.     e->entry = strdup(entry);
  106.     e->func = f;
  107.     e->arg = arg;
  108.     e->state = state;
  109.     e->keycode = key;
  110.     e->index = 0;
  111.     return e;
  112. }
  113.  
  114. /* calculate the length of an entry; this is:
  115.  * 2 (leading blanks) + strlen(e->entry) + 2 (trailing blanks) +
  116.  * (optional) some number of bytes for any key symbols
  117.  */
  118.  
  119. #define MAXKEYSYMLEN 4
  120.  
  121. int
  122. entrylen(e)
  123.     ENTRY *e;
  124. {
  125.     return 4 + strlen(e->entry) + (e->keycode ? 1 + strlen(UNALT(e->keycode)) :
  126.                      0);
  127. }
  128.  
  129. /*
  130.  * make a string representing a menu entry
  131.  */
  132.  
  133. char *
  134. entrystr(e, wide)
  135.     ENTRY *e;
  136.     int wide;
  137. {
  138.     int i, n;
  139.     char *s, *ret, c;
  140.  
  141.     n = wide + 1;
  142.     ret = malloc(n);
  143.     if (!ret) return 0;
  144.     i = 2;
  145.     c = '-';
  146.     for (s = e->entry; *s; s++) {
  147.         ret[i++] = *s;
  148.         if (*s != '-') c = ' ';
  149.         if (i == n) break;
  150.     }
  151.     ret[0] = c; ret[1] = c;            /* leading blanks or dashes */
  152.  
  153.     while (i < n-1)
  154.         ret[i++] = c;            /* trailing blanks or dashes */
  155.  
  156.     ret[n-1] = 0;
  157. /* special case for '-----' type strings */
  158.     if (c == '-') {
  159.         return ret;
  160.     }
  161.  
  162. /* special symbols for keyboard equivalents */
  163.     if (e->keycode) {
  164.         s = UNALT(e->keycode);
  165.         i = (n-2) - strlen(s);        /* right justify, trailing blank */
  166.         if (i > 3) {
  167.             while (*s)
  168.                 ret[i++] = *s++;
  169.         }
  170.     }
  171.     return ret;
  172. }
  173.  
  174. static OBJECT *
  175. fixmenu( bar )
  176.     MENU *bar;
  177. {
  178.     OBJECT *obj;
  179.     int i, wide, y, place;
  180.     int numobjects, num_titles, num_entries;
  181.     int menubox;
  182.     MENU *m; ENTRY *e;
  183.     char *s;
  184.  
  185.     numobjects = 4;    /* all menu bars needs some invisible boxes */
  186.     num_titles = 0;
  187.  
  188. /* count up the number of objects necessary */
  189.     for (m = bar; m; m = m->next) {
  190.         num_titles++;
  191.         numobjects++;        /* for the title */
  192.         numobjects++;        /* for the menu box */
  193.         for (e = m->contents; e; e = e->next) {
  194.             numobjects++;    /* for the entry */
  195.         }
  196.     }
  197.  
  198.     obj = malloc(numobjects * sizeof(OBJECT));
  199.     if (!obj) return obj;
  200.  
  201. /* now we create the various objects we need */
  202. /* first, the root menu bar object */
  203.     obj[0].ob_next = -1;
  204.     obj[0].ob_head = 1;
  205.     obj[0].ob_tail = num_titles + 3;
  206.     obj[0].ob_type = G_IBOX;
  207.     obj[0].ob_flags = NONE; obj[0].ob_state = NORMAL;
  208.     obj[0].ob_spec = 0L;
  209.     obj[0].ob_x = 0; obj[0].ob_y = 0;
  210.     obj[0].ob_width = 90; obj[0].ob_height = 25;
  211.  
  212. /* now the menu bar box itself */
  213.     obj[1].ob_next = obj[0].ob_tail;
  214.     obj[1].ob_head = 2;
  215.     obj[1].ob_tail = 2;
  216.     obj[1].ob_type = G_BOX;
  217.     obj[1].ob_flags = NONE; obj[1].ob_state = NORMAL;
  218.     obj[1].ob_spec = 0x00001100L;
  219.     obj[1].ob_x = 0; obj[1].ob_y = 0;
  220.     obj[1].ob_width = 90; obj[1].ob_height = 513;
  221.  
  222.     obj[2].ob_next = 1;
  223.     obj[2].ob_head = 3;
  224.     obj[2].ob_tail = 2 + num_titles;
  225.     obj[2].ob_type = G_IBOX;
  226.     obj[2].ob_flags = NONE; obj[2].ob_state = NORMAL;
  227.     obj[2].ob_spec = 0L;
  228.     obj[2].ob_x = 2; obj[2].ob_y = 0;
  229.     obj[2].ob_width = 0;        /* will be adjusted later */
  230.     obj[2].ob_height = 769;
  231.  
  232.     i = 3;
  233.     for (m = bar; m; m = m->next) {
  234.         m->index = i;
  235.         obj[i].ob_next = (m->next  == 0) ? 2 : i+1;
  236.         obj[i].ob_head = obj[i].ob_tail = -1;
  237.         obj[i].ob_type = G_TITLE;
  238.         obj[i].ob_flags = NONE; obj[i].ob_state = NORMAL;
  239.         obj[i].ob_width = strlen(m->title) + 2;
  240.         s = malloc(obj[i].ob_width + 1);
  241.         if (!s) return NULL;
  242.         s[0] = ' ';
  243.         strcpy(s+1, m->title);
  244.         strcat(s, " ");
  245.         obj[i].ob_spec = (long)s;
  246.         obj[i].ob_height = 769;
  247.         obj[i].ob_x = obj[2].ob_width;
  248.         obj[2].ob_width += obj[i].ob_width;
  249.         obj[i].ob_y = 0;
  250.         i++;
  251.     }
  252.     obj[i].ob_next = 0;
  253.     obj[i].ob_head = i+1;
  254.     obj[i].ob_tail = 0;        /* to be adjusted later */
  255.     menubox = i;
  256.     obj[i].ob_type = G_IBOX;
  257.     obj[i].ob_flags = NONE; obj[i].ob_state = NORMAL;
  258.     obj[i].ob_spec = 0L;
  259.     obj[i].ob_x = 0; obj[i].ob_y = 769;
  260.     obj[i].ob_width = 80; obj[i].ob_height = 19;
  261.     i++;
  262.  
  263. /* now, for each menu we calculate the number of entries and
  264.  * the size of the necessary box
  265.  */
  266.     place = 2;
  267.  
  268.     for (m = bar; m; m = m->next) {
  269.         int box;
  270.  
  271.         box = i;
  272.         num_entries = wide = 0;
  273.         for(e = m->contents; e; e = e->next) {
  274.             num_entries++;
  275.             if (m == deskmenu) {
  276.                 if (strlen(e->entry) > wide)
  277.                     wide = strlen(e->entry);
  278.             } else {
  279.                 if (entrylen(e) > wide)
  280.                     wide = entrylen(e);
  281.             }
  282.         }
  283.         if (m->next)
  284.             obj[i].ob_next = i + num_entries + 1;
  285.         else {
  286.             obj[i].ob_next = menubox;
  287.             obj[menubox].ob_tail = i;
  288.         }
  289.         obj[i].ob_head = i+1;
  290.         obj[i].ob_tail = i + num_entries;
  291.         obj[i].ob_type = G_BOX;
  292.         obj[i].ob_flags = NONE; obj[i].ob_state = NORMAL;
  293.         obj[i].ob_spec = 0x00ff1100L;
  294.         obj[i].ob_x = place; obj[i].ob_y = 0;
  295.         place += strlen(m->title)+2;
  296.         obj[i].ob_width = wide; obj[i].ob_height = num_entries;
  297.         i++;
  298.         y = 0;
  299.  
  300.         for (e = m->contents; e; e = e->next) {
  301.             e->index = i;
  302.             obj[i].ob_next = (e->next) ? i+1 : box;
  303.             obj[i].ob_head = obj[i].ob_tail = -1;
  304.             obj[i].ob_type = G_STRING;
  305.             obj[i].ob_flags = NONE;
  306.             obj[i].ob_state = e->state;
  307.     /* Do NOT malloc the strings for the Desk menu, or else there
  308.      * will be a memory leak!
  309.      */
  310.             if (m != deskmenu)
  311.                 s = entrystr(e, wide);
  312.             else {
  313.                 s = e->entry;
  314.             }
  315.             if (!s) return NULL;
  316.             obj[i].ob_spec = (long)s;
  317.             obj[i].ob_x = 0; obj[i].ob_y = y++;
  318.             obj[i].ob_width = wide; obj[i].ob_height = 1;
  319.             i++;
  320.         }
  321.     }
  322.     obj[i-1].ob_flags = LASTOB;
  323.  
  324. /* now, fix the object tree up */
  325.     for (i = 0; i < numobjects; i++)
  326.         rsrc_obfix(obj, i);
  327.  
  328.     return obj;
  329. }
  330.  
  331. void
  332. handle_menu(title, index)
  333.     int title, index;
  334. {
  335.     MENU *m;
  336.     ENTRY *e;
  337.  
  338.     for (m = deskmenu; m; m = m->next) {
  339.         if (m->index == title) break;
  340.     }
  341.     if (m) {
  342.         for (e = m->contents; e; e = e->next) {
  343.         if (e->index == index) {
  344.             (*e->func)(e->arg);
  345.             menu_tnormal(menuobj, title, 1);
  346.             return;
  347.         }
  348.         }
  349.     }
  350.  
  351. /* strange. Let's just punt and return */
  352. }
  353.  
  354. /*
  355.  * erase menu currently on screen (if one exists), and frees the memory
  356.  * allocated for its stri